home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
MIDIMOD2.ZIP
/
TEXTWINC.C
< prev
Wrap
Text File
|
1993-06-26
|
14KB
|
587 lines
/*
* TEXTWINC.C - Text-windowing system (Curses Version)
* (c)opyright Andrew Scott 1993
*
* Turbo C 2.0
*
* Description: Provides a simple text-menuing interface. Includes pop-down
* menus, and scrolling windows. To use, set up a main window
* with the MainWindow() function.
* eg. MainWindow("Title", 2, "Files", 'f', "Help", 'h');
*
* Then set the commands and command-numbers for each menu use
* the SetMenu function.
* eg. SetMenu(0, 3, "Open",'o',0, "Close",'c',1, "Quit",'q',2);
* SetMenu(1, 3, "Help",'h',3, "------------",-1,-1, "About",'a',4);
*
* Now just make a call to Choice() and the number it returns
* will be the command-number of the choice
* eg. If Help|About is chosen, 4 will be returned.
*
* If you want to get the user to select an option from a list
* of options, make an array of strings with the option
* descriptions in them (ensure final element is NULL). The
* element number chosen will be returned (first element = 0)
* after a call to ScrollChoice()
* eg. If the array is a, and the maximum string length is l, make the call
* ScrollChoice("BetterTitle", a, l);
*
* To display test inside a box, call DrawBox() with a NULL-
* terminated array of strings.
* eg. If the array is a, call
* DrawBox(a);
*
* To display text inside a box, and then wait for a key to be
* pressed, set up a NULL-terminated array of strings and call
* the InfoBox() function
* eg. If the array is a, make the call
* InfoBox(a);
*
* If you want to get input as well as print a box, make a call
* to DialogBox(), if nothing is entered, a default string is
* returned
* eg. DialogBox(a, "C:\") would return "C:\" if nothing was entered.
*
*
* Author: Andrew Scott (Adrenalin Software)
*
* Date: 14/3/1993 ver 0.1
* 17/4/1993 - converted to Curses (0.1a)
*/
#include <curses.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
/* Maximum number of chars in a menu title */
#define MAXMENUWIDTH 9
/* Maximum number of chars in a menu command */
#define MAXCOMMWIDTH 12
/* remove any old key definitions */
#ifdef KEY_UP
#undef KEY_UP
#undef KEY_DOWN
#undef KEY_LEFT
#undef KEY_RIGHT
#endif
/* wgetch returns these values for these keys when they're pressed */
#define CR '\r' /* sometimes '\n' */
#define BS '\b'
#define DEL 127
#define ESC 27
#define KEY_DOWN 0402
#define KEY_UP 0403
#define KEY_LEFT 0404
#define KEY_RIGHT 0405
typedef char *string;
struct MenuStruct {
char n[MAXCOMMWIDTH+1]; /* Item name ("" = no items) */
int k; /* Key-press selector (lower case) */
int x; /* Function reference number (-ve = no command) */
};
typedef struct MenuStruct *MenuItem;
struct MenuBar {
char n[MAXMENUWIDTH+1]; /* Menu name ("" = no menus) */
int k; /* Key-press selector (lower case) */
MenuItem m; /* Menu items */
} *MainW;
void MainWindow(string title, int num, ...)
/* Post: Screen is set up with a nice title and num menus */
{
va_list args;
string t;
int i;
struct MenuBar *c;
c = MainW = (struct MenuBar *) malloc(sizeof(struct MenuBar) * (num + 1));
va_start(args, num);
initscr();
raw(); /* startup mode.. use either this or cbreak() */
noecho();
keypad(stdscr, TRUE);
scrollok(stdscr, FALSE);
werase(stdscr);
wmove(stdscr, 0, (COLS - strlen(title))/2);
wprintw(stdscr, "%s", title);
wmove(stdscr, 1, 1);
for (i = num; i--; c++) {
t = (va_arg(args, string));
strcpy(c->n, t);
wprintw(stdscr, "%-*s", MAXMENUWIDTH, t);
c->k = (va_arg(args, int));
c->m = NULL;
}
c->n[0] = 0;
va_end(args);
refresh();
}
void EndWindows()
/* Post: Windows are freed up */
{
struct MenuBar *c;
MenuItem t;
for (c = MainW; c->n[0]; c++)
free(c->m);
free(MainW);
delwin(curscr);
endwin();
}
void SetMenu(int menu, int n, ...)
/* Post: n commands has been set in menu #menu (0 = 1st) */
{
va_list args;
string t;
struct MenuBar *c1;
MenuItem c2;
int i;
for (i = menu, c1 = MainW; i-- && c1->n[0]; c1++);
if (! c1->n[0])
return; /* error */
c1->m = c2 = (MenuItem) malloc(sizeof(struct MenuStruct) * (n + 1));
va_start(args, n);
for (; n--; c2++) {
t = va_arg(args, string);
strcpy(c2->n, t);
c2->k = va_arg(args, int);
c2->x = va_arg(args, int);
}
c2->n[0] = 0;
}
WINDOW *MenuWin = NULL; /* ignore this unstructured global variable ;) */
void PrintMenu(MenuItem m, int x)
/* Post: The menu which is pointed to by m is printed at column x */
{
int i;
MenuItem t;
if (MenuWin != NULL) {
werase(MenuWin);
wrefresh(MenuWin);
delwin(MenuWin);
}
for (i=0, t=m; t->n[0]; i++, t++);
MenuWin = newwin(i+2, MAXCOMMWIDTH+4, 2, x-1);
box(MenuWin, 0, 0);
for (i=1; m->n[0]; i++) {
wmove(MenuWin, i, 2);
waddstr(MenuWin, (m++)->n);
}
wrefresh(MenuWin);
}
void ClearMenu()
/* Post: The last menu printed is now gone */
{
werase(MenuWin);
wrefresh(MenuWin);
}
void PrintComm(MenuItem m, int y)
/* Post: Item *m is highlighted in current menu, position y */
{
wmove(MenuWin, y+1, 1);
wprintw(MenuWin, "[%-*s]", MAXCOMMWIDTH, m->n);
}
void ClearComm(MenuItem m, int y)
/* Post: Item *m is normalized in current menu, position y */
{
wmove(MenuWin, y+1, 1);
wprintw(MenuWin, " %-*s ", MAXCOMMWIDTH, m->n);
}
void PrintBar(WINDOW *SWin, string s, int w, int y)
/* Post: String s (width w) is highlighted in the window SWin on line y */
{
wmove(SWin, y, 0);
wprintw(SWin, "[%-*s]", w, s);
}
void ClearBar(WINDOW *SWin, string s, int w, int y)
/* Post: String s (width w) is normalized in the window SWin on line y */
{
wmove(SWin, y, 0);
wprintw(SWin, " %-*s ", w, s);
}
void Beep()
/* Post: Speaker has made a beep */
{
beep(); /* delete this line if your curses throw up on it */
}
int Choice()
/*
* Returns: a function reference number corresponding to a chosen command,
* but returns -1 on an error.
*/
{
int ch;
struct MenuBar *c;
MenuItem p, q;
int i, fx = -1, y;
do {
wmove(stdscr, LINES-1, 0);
wprintw(stdscr, "Press the letter of the menu you wish to select.");
refresh();
ch = tolower(wgetch(stdscr));
for (c = MainW, i = 0; c->n[0] && c->k != ch; c++, i++);
i = MAXMENUWIDTH * i;
if (c->n[0] != 0)
do {
wmove(stdscr, LINES-1, 0);
wprintw(stdscr, "Press a letter, or use cursor keys and <RETURN> to select a command.");
wmove(stdscr, 1, i);
wprintw(stdscr, "[%s]", c->n);
refresh();
PrintMenu(p = c->m, i+1);
PrintComm(p, y = 0);
do {
wrefresh(MenuWin);
ch = tolower(wgetch(MenuWin));
if (ch==KEY_UP) /** up-arrow */
if (!y)
Beep();
else {
ClearComm(p--, y--);
PrintComm(p, y);
}
else if (ch==KEY_DOWN) /** down-arrow */
if (! (p+1)->n[0])
Beep();
else {
ClearComm(p++, y++);
PrintComm(p, y);
}
else {
for (q = c->m; q->n[0] && q->k != ch; q++);
if (q->n[0])
fx = q->x;
}
} while ((ch==KEY_UP || ch==KEY_DOWN) && fx < 0);
if (ch==CR && fx < 0) /** return */
fx = p->x;
ClearMenu();
wmove(stdscr, 1, i);
wprintw(stdscr, " %s ", c->n);
wmove(stdscr, LINES-1, 0);
wclrtoeol(stdscr);
if (ch==KEY_LEFT) /** left-arrow */
if (!i)
Beep();
else {
i -= MAXMENUWIDTH;
c--;
}
else if (ch==KEY_RIGHT) /** right-arrow */
if (! (c+1)->n[0])
Beep();
else {
i += MAXMENUWIDTH;
c++;
}
} while (ch != ESC && fx < 0);
} while (fx < 0);
refresh();
return fx;
}
void ClearWin()
/* Post: Area below command and title bars is clear */
{
wmove(stdscr, 2, 0);
wclrtobot(stdscr);
refresh();
}
int ScrollChoice(string title, string *sp, int w)
/*
* Returns: The offset of the string from s which is chosen, -1 on none
* s points to the start of a list of strings, max length w, NULL term.
*/
{
string *srt, *end;
int l, p, cur, ch, x = -1;
WINDOW *ScrWin, *BorderWin;
if (*sp==NULL) /* have to have at least 1 thing to print */
return -1;
if (strlen(title) > w)
w = strlen(title);
wmove(stdscr, LINES-1, 0);
wprintw(stdscr, "Use cursor keys and <RETURN> to make a selection.");
refresh();
for (end = sp, l = 0; *end!=NULL && l < LINES-5; end++, l++);
BorderWin = newwin(l+2, w+4, 2, 4);
box(BorderWin, 0, 0);
wrefresh(BorderWin);
ScrWin = newwin(l, w+2, 3, 5);
scrollok(ScrWin, FALSE);
keypad(ScrWin, TRUE);
p = l;
srt = end;
while (p--) {
wmove(ScrWin, p, 1);
waddstr(ScrWin, *(--srt));
}
PrintBar(ScrWin, *srt, w, p = 0);
cur = 0;
do {
wrefresh(ScrWin);
ch = tolower(wgetch(ScrWin));
if (ch==KEY_UP)
if (!cur)
Beep();
else if (p) {
ClearBar(ScrWin, *(srt+p), w, p);
p--;
PrintBar(ScrWin, *(srt+p), w, p);
cur--;
} else {
ClearBar(ScrWin, *(srt--), w, 0);
wmove(ScrWin, 0, 0);
winsertln(ScrWin);
PrintBar(ScrWin, *srt, w, 0);
end--;
cur--;
}
else if (ch==KEY_DOWN)
if (p==l-1 && *end==NULL)
Beep();
else if (p < l-1) {
ClearBar(ScrWin, *(srt+p), w, p);
p++;
cur++;
PrintBar(ScrWin, *(srt+p), w, p);
} else {
ClearBar(ScrWin, *(end-1), w, p);
wmove(ScrWin, 0, 0);
wdeleteln(ScrWin);
cur++;
PrintBar(ScrWin, *end, w, p);
end++;
srt++;
}
else if (ch==CR)
x = cur;
} while (x < 0 && ch != ESC);
delwin(ScrWin);
werase(BorderWin);
wrefresh(BorderWin);
delwin(BorderWin);
ClearWin();
return x;
}
WINDOW *PrintBox(string *sp, int *x, int *y, int *w)
/*
* Returns: The window in which the NULL-terminated array of strings pointed
* to by sp is printed, y is set to be the offset to the bottom of the
* window, and w is the width of it.
*/
{
int w1, i, j, k;
string *c;
WINDOW *BoxWin;
if (*sp==NULL)
return NULL;
c = sp;
for (w1 = strlen(*(c++)), i = 1; *c!=NULL; c++, i++)
if (w1 < (j = strlen(*c)))
w1 = j;
j = 1 + (LINES - 5 - i)/2;
*y = j + i;
*w = k = w1 += 2;
w1 = (COLS - 2 - w1)/2;
*x = w1 + 1;
BoxWin = newwin(i+2, k+2, j, w1);
box(BoxWin, 0, 0);
for (i = 1, c = sp; *c!=NULL; c++) {
wmove(BoxWin, i++, 2);
waddstr(BoxWin, *c);
}
wrefresh(BoxWin);
return BoxWin;
}
void DrawBox(string *sp)
/* Post: The NULL-terminated array of strings pointed to by sp is printed */
{
int k;
delwin(PrintBox(sp, &k, &k, &k));
}
char InfoBox(string *sp)
/*
* Returns: The key pressed after the NULL-terminated array of strings
* pointed to by sp is printed.
*/
{
int k;
WINDOW *BoxWin;
wmove(stdscr, LINES-1, 0);
waddstr(stdscr, "Please press a key.");
refresh();
BoxWin = PrintBox(sp, &k, &k, &k);
k = wgetch(stdscr);
werase(BoxWin);
wrefresh(BoxWin);
delwin(BoxWin);
ClearWin();
return k;
}
string DialogBox(string *sp, string def)
/* Pre: def != NULL */
/*
* Returns: The string entered (or def if none entered), after printing
* box filled with NULL-terminated strings sp.
*/
{
int x, y, w, ch, i=0;
string s;
WINDOW *DiagWin, *TextWin;
wmove(stdscr, LINES-1, 0);
waddstr(stdscr, "Enter text, and when you are finished, press <RETURN>.");
refresh();
DiagWin = PrintBox(sp, &x, &y, &w);
s = (string) malloc(w+1);
strcpy(s, def);
TextWin = newwin(1, w, y, x);
scrollok(TextWin, FALSE);
keypad(TextWin, TRUE);
wmove(TextWin, 0, 0);
waddstr(TextWin, s);
wmove(TextWin, 0, 0);
x = strlen(s);
do {
wrefresh(TextWin);
ch = wgetch(TextWin);
if (ch==BS || ch==DEL)
if (!i)
Beep();
else {
wprintw(TextWin, "\b");
wclrtoeol(TextWin);
x = --i;
}
else if (ch==KEY_LEFT)
if (!i)
Beep();
else {
wprintw(TextWin, "\b");
i--;
}
else if (ch==KEY_RIGHT)
if (i==x)
Beep();
else {
waddch(TextWin, s[i]);
i++;
}
else if (ch>31 && ch<127)
if (i==w-1)
Beep();
else {
waddch(TextWin, ch);
if (i==x)
x++;
s[i++] = ch;
}
} while (ch!=CR && ch!=ESC);
s[i] = 0;
if (ch==ESC) {
free(s);
strcpy(s = (string) malloc(strlen(def)+1), def);
}
delwin(TextWin);
werase(DiagWin);
wrefresh(DiagWin);
delwin(DiagWin);
ClearWin();
return s;
}
/*
* This main function is for testing the basics of these routines.
* Leave it commented out when creating object files.
*
main()
{
string scrolly[] = {
"First one",
"Second option",
"3rd",
"4th",
"Fifth",
"This could go on for AGES",
"Why not stop soon?",
"Ok",
"How about the next one",
"Done",
"Nope",
"Here's another few..",
"Un",
"Deux",
"Trois",
"Quatre",
"When should I stop?",
"Not yet obviously.",
"Cinq",
"Six",
"Sept",
"I think that's enough",
"Well maybe one more.",
NULL
};
string diagbox[] = {
"Please enter some gibberish",
"below at the prompt please.",
"It WONT check your spelling.",
"",
"",
NULL
};
string s;
MainWindow("Big Huge Title", 3, "Ace", 'a', "Bee", 'b', "seaCide", 'c');
SetMenu(0, 3, "First", 'f', 1, "------------", -1, -1, "Second", 's', 2);
SetMenu(1, 1, "Spelling", 's', 3);
SetMenu(2, 2, "I'd like", 'i', 4, "To be beside", 't', 5);
while (1)
switch (Choice()) {
case 1:
ScrollChoice("Window Name", scrolly, 25);
break;
case 3:
s = DialogBox(diagbox, "sample");
free(s);
break;
case 5:
exit(0);
}
}
* Ok.. this ends the commented out part
*/